package cn.melonlib.cores.commons.comp.web.ctrl;

import cn.hutool.core.bean.BeanUtil;
import cn.melonlib.cores.commons.comp.utils.EntityWrapperContainer;
import cn.melonlib.cores.commons.comp.web.anno.ControllerConfig;
import cn.melonlib.cores.commons.comp.web.anno.EntityConfig;
import cn.melonlib.cores.commons.model.entity.IEntity;
import cn.melonlib.cores.jpa.model.bean.collections.EntityMap;
import cn.melonlib.cores.jpa.model.bean.impl.OffsetQueryImpl;
import cn.melonlib.cores.jpa.model.bean.impl.PaginationList;
import cn.melonlib.objects.maps.JsonMap;
import lombok.Getter;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.hibernate.service.spi.ServiceException;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Pattern;

import static java.util.stream.Collectors.toList;

@ControllerConfig
@EntityConfig
@Getter
public class RestfulController<ENTITY extends IEntity<? extends Serializable>> extends BasicController {

    private Class<ENTITY> entityClass;

    private String offsetName;

    private String firstName;

    private String dataTotalName;

    private String requestStatusName;

    private String requestCodeName;

    private int dataDefaultLimit;

    private String datasName;

    private String searchParamsPrefix;

    private String formParamsPrefix;

    private String sortFields;

    private String saveSuccess;

    private String removeSuccess;

    @PostConstruct
    public void init() {
        System.out.println("注册服务接口" + this.getClass().getName());
        entityClass = (Class<ENTITY>) ResolvableType.forClass(this.getClass()).getSuperType().getGeneric(0).resolve();
        ControllerConfig controllerConfig = AnnotationUtils.findAnnotation(this.getClass(), ControllerConfig.class);
        EntityConfig entityConfig = AnnotationUtils.findAnnotation(this.getClass(), EntityConfig.class);
        offsetName = controllerConfig.offsetParamName();
        firstName = controllerConfig.limitParamName();
        dataTotalName = controllerConfig.dataTotalName();
        requestStatusName = controllerConfig.requestStatusName();
        requestCodeName = controllerConfig.requestCodeName();
        dataDefaultLimit = controllerConfig.dataDefaultLimit();
        datasName = controllerConfig.datasName();
        searchParamsPrefix = entityConfig.searchParamsPrefix();
        formParamsPrefix = entityConfig.formParamsPrefix();
        sortFields = entityConfig.sortFields();
        saveSuccess = entityConfig.saveSuccess();
        removeSuccess = entityConfig.removeSuccess();
    }


    @PostMapping(path = {"search.api"}, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public String search(@RequestBody JsonMap<Object> params) throws Exception {
        Integer first = ObjectUtils.defaultIfNull((Number) BeanUtil.getProperty(params, firstName)
                , 20).intValue(), offset = ObjectUtils.defaultIfNull((Number) BeanUtil.getProperty(params, offsetName), 0).intValue();
        PaginationList<EntityMap<Object, ENTITY>> entities = this.basicService.<PaginationList<EntityMap<Object, ENTITY>>>
                        search(new OffsetQueryImpl(this.entityClass, JsonMap.<JsonMap<Object>>createMap((Map<String, JsonMap<Object>>) params.get(searchParamsPrefix)), offset, first))
                .getResult();
        return createResponseByStatus(true).append(dataTotalName, entities.getTotal()).append(datasName, transDatas(entities)).jsonString();
    }

    /**
     * 修改数据返回结果
     *
     * @param entities
     * @return
     * @throws Exception
     */
    protected List<EntityMap<Object, ENTITY>> transDatas(List<EntityMap<Object, ENTITY>> entities) throws Exception {
        return entities.stream().map(this.listMap())
                .parallel().map(syncMap()).collect(toList());
    }

    /**
     * 修改数据每行数据结果
     *
     * @return
     * @throws Exception
     */
    protected Function<EntityMap<Object, ENTITY>, EntityMap<Object, ENTITY>> listMap() throws Exception {
        return f -> f;
    }

    protected Function<EntityMap<Object, ENTITY>, EntityMap<Object, ENTITY>> syncMap() throws Exception {
        return f -> f;
    }

    @PostMapping(path = {"create.api"}, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public String create(@RequestBody JsonMap<Object> body) throws Exception {
        ENTITY entity = this.entityWrapperContainer.wrap(EntityWrapperContainer.JSON, body.jsonString(), this.entityClass);
        IEntity<? extends Serializable> entityResult = this.basicService.save(entity).getResult();
        return createResponseByStatus(true).append("msg", saveSuccess).append("entity", new EntityMap<Object, IEntity<? extends Serializable>>(entityResult)).jsonString();
    }

    @PutMapping(path = {"{id}.api"}, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public String put(@RequestBody JsonMap<Object> body, @PathVariable("id") String id) throws Exception {
        if (Objects.equals(id, body.get("id"))) {
            ENTITY entity = this.entityWrapperContainer.wrap(EntityWrapperContainer.JSON, body.jsonString(), this.entityClass);
            IEntity<? extends Serializable> entityResult = this.basicService.save(entity).getResult();
            return createResponseByStatus(true).append("msg", saveSuccess).append("entity", new EntityMap<Object, IEntity<? extends Serializable>>(entityResult)).jsonString();
        } else {
            throw new ServiceException("提交的主键不匹配");
        }
    }

    protected void beforeSave(ENTITY entity) {

    }

    protected void postSave(ENTITY entity) {

    }

    @DeleteMapping(path = {"{id}.api"}, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
    public String remove(@PathVariable("id") String id) throws Exception {
        this.basicService.removeById(entityClass, id);
        return createResponseByStatus(true).append("msg", saveSuccess).jsonString();
    }


    public static Pattern fullUrlRegex = Pattern.compile("^https?://.*$");
    public static Pattern rootUrlRegex = Pattern.compile("^/.*$");
    public static Pattern currentUrlRegex = Pattern.compile("^\\./.*$");

    public Object loadApiData(String pathRoot, String path, String cookie) throws Exception {
        String controllerPath = AnnotationUtils.getAnnotation(this.getClass(), RequestMapping.class).path()[0];
//		RequestBody body=RequestBody.create($this$toRequestBody, this.mediaType);
        StringBuilder fpath = new StringBuilder();
        if (fullUrlRegex.matcher(path).matches()) {
            this.logger.info("访问外部网站。");
        } else if (rootUrlRegex.matcher(path).matches()) {
            fpath.append(pathRoot);
            this.logger.info("访问内部网站，从根路径访问。");
        } else if (currentUrlRegex.matcher(path).matches()) {
            fpath.append(pathRoot).append(controllerPath).append("/");
            this.logger.info("访问内部网站，当前功能访问。");
        } else {
            fpath.append(pathRoot).append(controllerPath).append("/");
            this.logger.info("访问内部网站，当前功能访问：");
        }
        fpath.append(path);
        this.logger.info("访问链接：" + fpath);
        Request req = new Request.Builder().url(fpath.toString()).get().addHeader("cookie", cookie).build();
        try (Response resp = httpClient.newCall(req).execute()) {
            String body = resp.body().string();
            logger.info(body);
            Map<String, Object> bodyMap = this.jsonMapper.readValue(body, Map.class);
            if (BooleanUtils.isTrue((Boolean) ObjectUtils.defaultIfNull(bodyMap.get(this.requestStatusName), false))) {
                return bodyMap.get(this.datasName);
            } else {
                return bodyMap;
            }

        }
    }
}
